package cn.bytest.netty.code;

import cn.bytest.netty.NettyChannel;
import cn.bytest.netty.serialize.GsonSerialize;
import cn.bytets.rpc.api.code.Codec;
import cn.bytets.rpc.api.serialize.RpcSerialize;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;

import java.util.List;

/**
 * Netty解码
 */
public class NettyCodecAdapter{

    private final ChannelHandler encoder = new InternalEncoder();

    private final ChannelHandler decoder = new InternalDecoder();

    private RpcSerialize serialize;

    private Codec codec;

    public NettyCodecAdapter(){}

    public NettyCodecAdapter(Codec codec){
        this.codec = codec;
    }

    public ChannelHandler getEncoder() {
        return encoder;
    }

    public ChannelHandler getDecoder() {
        return decoder;
    }

    /**
     * 这里可以使用SPI动态扩展
     * @return
     */
    public synchronized RpcSerialize getSerialize(){
        if(null==this.serialize){
            this.serialize = new GsonSerialize();
        }
        return this.serialize;
    }
    /**
     * 编码
     */
    private class InternalEncoder extends MessageToByteEncoder{

        @Override
        protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
            Channel channel = ctx.channel();
            NettyChannel nettyChannel = NettyChannel.getOrAddChannel(channel);
            try {
                codec.encode(msg, new NettyChannelByteBuf(out), NettyCodecAdapter.this.getSerialize(),nettyChannel);
            } catch (Exception e){
                e.printStackTrace();
                throw e;
            } finally {
                NettyChannel.removeChannelIfDisconnected(channel);
            }
        }
    }

    /**
     * 解码
     */
    private class InternalDecoder extends ByteToMessageDecoder{

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            Channel channel = ctx.channel();
            NettyChannel nettyChannel = NettyChannel.getOrAddChannel(channel);
            try{
                if ((in.writerIndex()-in.readerIndex())<16){
                    System.out.println("数据小于16个字节");
                    return;
                }
                out.add(codec.decoder(new NettyChannelByteBuf(in),NettyCodecAdapter.this.getSerialize(),nettyChannel));
            } catch (Exception e){
                e.printStackTrace();
                throw e;
            } finally {
                NettyChannel.removeChannelIfDisconnected(channel);
            }
        }
    }

}
